#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Neo4j自然语言查询工具
功能：简化的Neo4j知识图谱查询接口
"""

from neo4j import GraphDatabase
import jieba
import re
import sys


class SimpleNeo4jQuery:
    def __init__(self, uri="bolt://localhost:7687", user="neo4j", password="changsha2025"):
        try:
            self.driver = GraphDatabase.driver(uri, auth=(user, password))
            print(f"✅ 成功连接到Neo4j数据库")
        except Exception as e:
            print(f"❌ 连接Neo4j失败: {e}")
            print("请确保Neo4j服务正在运行，并检查连接参数")
            self.driver = None
    
    def close(self):
        if self.driver:
            self.driver.close()
    
    def simple_query(self, query_text: str, show_cypher=True):
        """简化的自然语言查询"""
        if not self.driver:
            print("❌ 数据库连接不可用")
            return []

        # 提取关键词
        keywords = self._extract_keywords(query_text)
        print(f"🔍 搜索关键词: {keywords}")

        if show_cypher:
            print(f"\n📝 执行的Cypher查询语句:")
            print("=" * 60)

        results = []
        
        with self.driver.session() as session:
            # 查询策略1: 产品相关问题
            for keyword in keywords:
                if re.match(r'[A-Z]{1,3}\d{3,4}', keyword.upper()):
                    # 产品编号查询 - 查询决策节点
                    cypher = """
                        MATCH (p:Product {code: $product})-[:HAS_ISSUE*1..10]->(n:DecisionNode)
                        RETURN p.code as product, n.content as content, n.type as type
                        ORDER BY n.level
                        LIMIT 20
                    """
                    try:
                        result = session.run(cypher, product=keyword.upper())
                        for record in result:
                            results.append({
                                'type': 'product_info',
                                'product': record['product'],
                                'content': record['content'],
                                'node_type': record['type']
                            })
                    except Exception as e:
                        print(f"⚠️  产品决策节点查询失败: {e}")

                    # 产品编号查询 - 查询文本节点
                    cypher = """
                        MATCH (p:Product {code: $product})-[:MENTIONED_IN]->(t:TextNode)
                        RETURN p.code as product, t.content as content, 'text' as type
                        LIMIT 10
                    """
                    try:
                        result = session.run(cypher, product=keyword.upper())
                        for record in result:
                            results.append({
                                'type': 'product_info',
                                'product': record['product'],
                                'content': record['content'],
                                'node_type': record['type']
                            })
                    except Exception as e:
                        print(f"⚠️  产品文本节点查询失败: {e}")
            
            # 查询策略2: 内容关键词匹配
            for keyword in keywords:
                if len(keyword) > 1:
                    # 在决策节点中搜索
                    cypher = """
                        MATCH (n:DecisionNode)
                        WHERE n.content CONTAINS $keyword
                        RETURN n.product as product, n.content as content, n.type as type, n.filename as filename
                        LIMIT 10
                    """
                    try:
                        result = session.run(cypher, keyword=keyword)
                        for record in result:
                            results.append({
                                'type': 'keyword_match',
                                'product': record['product'],
                                'content': record['content'],
                                'node_type': record['type'],
                                'matched_keyword': keyword,
                                'filename': record.get('filename', '')
                            })
                    except Exception as e:
                        print(f"⚠️  决策节点关键词查询失败: {e}")

                    # 在文本节点中搜索
                    cypher = """
                        MATCH (t:TextNode)
                        WHERE t.content CONTAINS $keyword
                        RETURN t.product as product, t.content as content, 'text' as type, t.filename as filename
                        LIMIT 10
                    """
                    try:
                        result = session.run(cypher, keyword=keyword)
                        for record in result:
                            results.append({
                                'type': 'keyword_match',
                                'product': record['product'],
                                'content': record['content'],
                                'node_type': record['type'],
                                'matched_keyword': keyword,
                                'filename': record.get('filename', '')
                            })
                    except Exception as e:
                        print(f"⚠️  文本节点关键词查询失败: {e}")
            
            # 查询策略3: 问题-解决方案路径
            for keyword in keywords:
                cypher = """
                    MATCH (problem:DecisionNode {type: 'problem'})
                    WHERE problem.content CONTAINS $keyword
                    MATCH path = (problem)-[:LEADS_TO*1..5]->(solution:DecisionNode {type: 'solution'})
                    RETURN problem.product as product, problem.content as problem, solution.content as solution
                    LIMIT 5
                """
                try:
                    result = session.run(cypher, keyword=keyword)
                    for record in result:
                        results.append({
                            'type': 'problem_solution',
                            'product': record['product'],
                            'problem': record['problem'],
                            'solution': record['solution']
                        })
                except Exception as e:
                    print(f"⚠️  问题-解决方案查询失败: {e}")
        
        return self._deduplicate_results(results)
    
    def _extract_keywords(self, text: str):
        """提取关键词"""
        # 产品编号
        products = re.findall(r'[A-Z]{1,3}\d{3,4}', text.upper())
        
        # 分词
        words = list(jieba.cut(text))
        keywords = []
        
        # 过滤关键词
        stop_words = {'的', '是', '有', '和', '怎么', '什么', '吗', '呢', '了'}
        for word in words:
            word = word.strip()
            if len(word) > 1 and word not in stop_words:
                keywords.append(word)
        
        return products + keywords
    
    def _deduplicate_results(self, results):
        """去重结果"""
        seen = set()
        unique_results = []
        
        for result in results:
            # 创建唯一标识
            if result['type'] == 'problem_solution':
                key = f"{result['product']}-{result['problem']}-{result['solution']}"
            else:
                key = f"{result['product']}-{result['content']}"
            
            if key not in seen:
                seen.add(key)
                unique_results.append(result)
        
        return unique_results
    
    def display_results(self, results, query):
        """显示查询结果"""
        if not results:
            print(f"\n❌ 没有找到关于 '{query}' 的相关信息")
            return
        
        print(f"\n🎯 查询结果 (共{len(results)}条):")
        print("=" * 60)
        
        # 按类型分组显示
        problem_solutions = [r for r in results if r['type'] == 'problem_solution']
        other_results = [r for r in results if r['type'] != 'problem_solution']
        
        # 优先显示问题-解决方案
        if problem_solutions:
            print("\n💡 问题解决方案:")
            for i, result in enumerate(problem_solutions[:5], 1):
                print(f"\n{i}. 产品: {result['product']}")
                print(f"   问题: {result['problem']}")
                print(f"   解决方案: {result['solution']}")
        
        # 显示其他相关信息
        if other_results:
            print(f"\n📋 其他相关信息:")
            for i, result in enumerate(other_results[:5], 1):
                print(f"\n{i}. 产品: {result['product']}")
                print(f"   类型: {result['node_type']}")
                print(f"   内容: {result['content']}")
                if 'matched_keyword' in result:
                    print(f"   匹配词: {result['matched_keyword']}")
    
    def get_product_overview(self, product_code: str):
        """获取产品概览"""
        if not self.driver:
            return
        
        with self.driver.session() as session:
            cypher = """
                MATCH (p:Product {code: $product})-[:HAS_PROBLEM*1..10]->(n:Node)
                RETURN n.content as content, n.type as type, n.level as level
                ORDER BY n.level
            """
            try:
                result = session.run(cypher, product=product_code.upper())
                
                print(f"\n📦 {product_code} 产品信息概览:")
                print("=" * 40)
                
                current_level = 0
                for record in result:
                    level = record['level']
                    content = record['content']
                    node_type = record['type']
                    
                    if level != current_level:
                        current_level = level
                        print(f"\n📍 级别 {level}:")
                    
                    print(f"   {node_type}: {content}")
                    
            except Exception as e:
                print(f"❌ 获取产品信息失败: {e}")


def interactive_query():
    """交互式查询"""
    print("🔍 Neo4j知识图谱查询工具")
    print("=" * 40)
    print("💡 支持自然语言查询决策树知识库")
    print("💡 输入 'overview PK511' 查看产品概览")
    print("💡 输入 'quit' 退出")
    print("=" * 40)
    
    query_tool = SimpleNeo4jQuery()
    
    if not query_tool.driver:
        return
    
    try:
        while True:
            query = input("\n🔍 请输入查询: ").strip()
            
            if query.lower() in ['quit', 'exit', '退出']:
                print("👋 再见!")
                break
            
            if not query:
                continue
            
            # 检查是否是概览查询
            if query.lower().startswith('overview '):
                product = query.split(' ', 1)[1].strip()
                query_tool.get_product_overview(product)
                continue
            
            # 执行自然语言查询
            results = query_tool.simple_query(query)
            query_tool.display_results(results, query)
    
    finally:
        query_tool.close()


def command_line_query():
    """命令行查询"""
    if len(sys.argv) < 2:
        print("用法: python neo4j_query_tool.py '查询问题'")
        print("示例: python neo4j_query_tool.py 'PK511无产物'")
        return
    
    query = ' '.join(sys.argv[1:])
    
    query_tool = SimpleNeo4jQuery()
    if not query_tool.driver:
        return
    
    try:
        results = query_tool.simple_query(query)
        query_tool.display_results(results, query)
    finally:
        query_tool.close()


if __name__ == "__main__":
    if len(sys.argv) > 1:
        command_line_query()
    else:
        interactive_query()
